package org.atlassian.plugins.fisheyeAutoReview;

import java.util.Arrays;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.atlassian.crucible.spi.PluginId;
import com.atlassian.crucible.spi.data.ChangesetData;
import com.atlassian.crucible.spi.data.GeneralCommentData;
import com.atlassian.crucible.spi.data.ProjectData;
import com.atlassian.crucible.spi.data.ReviewData;
import com.atlassian.crucible.spi.services.ImpersonationService;
import com.atlassian.crucible.spi.services.Operation;
import com.atlassian.crucible.spi.services.ProjectService;
import com.atlassian.crucible.spi.services.ReviewService;
import com.atlassian.crucible.spi.services.SearchService;
import com.atlassian.event.Event;
import com.atlassian.event.EventListener;
import com.atlassian.fisheye.event.CommitEvent;
import com.atlassian.fisheye.spi.data.ChangesetDataFE;
import com.atlassian.fisheye.spi.services.RevisionDataService;

public class CommitListener implements EventListener {

	private static final Logger log = LoggerFactory
			.getLogger(CommitListener.class);

	private ProjectService projectService;
	private ReviewService reviewService;
	private SearchService searchService;
	private RevisionDataService revisionDataService;
	private ImpersonationService impersonationService;
	private PluginId pluginId;

	@Autowired
	public void setProjectService(ProjectService projectService) {
		this.projectService = projectService;
	}

	@Autowired
	public void setReviewService(ReviewService reviewService) {
		this.reviewService = reviewService;
	}

	@Autowired
	public void setSearchService(SearchService searchService) {
		this.searchService = searchService;
	}

	@Autowired
	public void setRevisionDataService(RevisionDataService revisionDataService) {
		this.revisionDataService = revisionDataService;
	}

	@Autowired
	public void setImpersonationService(
			ImpersonationService impersonationService) {
		this.impersonationService = impersonationService;
	}

	@Autowired
	public void setPluginId(PluginId pluginId) {
		this.pluginId = pluginId;
	}

	// @com.atlassian.event.api.EventListener
	public void onEvent(final CommitEvent event) throws Exception {

		ChangesetDataFE changeSet = revisionDataService.getChangeset(event
				.getRepositoryName(), event.getChangeSetId());
		final String comment = changeSet.getComment();

		impersonationService.doAsUser(pluginId, changeSet.getAuthor(),
				new Operation<Void, Exception>() {
					@Override
					public Void perform() throws Exception {
						Set<String> idTokens = new HashSet<String>();
						for (ProjectData project : projectService
								.getAllProjects()) {
							Pattern p = Pattern.compile("(" + project.getKey()
									+ "-[0-9]+)");
							Matcher m = p.matcher(comment);

							while (m.find()) {
								idTokens.add(m.group());
							}
						}

						for (String idToken : idTokens) {
							Set<ReviewData> reviews = new HashSet<ReviewData>(
									searchService.searchForReviews(idToken));

							for (final ReviewData review : reviews) {

								GeneralCommentData newComment = new GeneralCommentData();
								newComment.setMessage(ResourceBundle.getBundle(
										"strings").getString("comment.prefix")
										+ "\n" + comment);
								reviewService.addGeneralComment(review
										.getPermaId(), newComment);
								reviewService
										.addChangesetsToReview(
												review.getPermaId(),
												event.getRepositoryName(),
												Arrays
														.asList(new ChangesetData[] { new ChangesetData(
																event
																		.getChangeSetId()) }));

							}
						}
						return null;
					}
				});
	}

	@Override
	public Class<?>[] getHandledEventClasses() {
		return new Class[] { CommitEvent.class };
	}

	@Override
	public void handleEvent(Event event) {
		try {
			onEvent((CommitEvent) event);
		} catch (Exception e) {
			log.error(e.getLocalizedMessage(), e);
		}
	}
}
